home *** CD-ROM | disk | FTP | other *** search
/ Aminet 52 / Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso / Aminet / comm / www / surfboard-mos.lha / surfboard / surfboard.c < prev    next >
C/C++ Source or Header  |  2002-10-23  |  22KB  |  807 lines

  1. #include <errno.h>       /* obligatory includes */
  2. #include <signal.h>
  3. #include <stdio.h>
  4. #include <unistd.h>
  5. #include <sys/types.h>
  6. #include <sys/socket.h>
  7. #include <sys/wait.h>
  8. #include <sys/stat.h>
  9. #include <netinet/in.h>
  10. #include <netdb.h>
  11. #include <fcntl.h>
  12.  
  13. #include <time.h>
  14.  
  15. #include <sys/stat.h>
  16. #include <unistd.h>
  17.  
  18. /* Log level constants */
  19. #define LOG_DEBUG 0
  20. #define LOG_MSG 1
  21. #define LOG_REQ 2
  22. #define LOG_ERR 3
  23.  
  24. #define VERSION "Meredydd Luff's Surfboard/1.1.6 (UNIX/beta)"
  25.  
  26. #define CGI_ENV_LEN 64
  27. /*      ^^^^^^^^^^^ = max. number of environment variables for CGI script*/
  28.  
  29. char hostname[1024]="";
  30.  
  31. /* This can be overridden from the command line */
  32. char conffile[1024] = "/etc/surfboard/surfboard.conf";
  33.  
  34. /* All of these can be overridden from the config file */
  35. char docroot[1024] = "/pub";
  36. char logfile[1024] = "/var/log/surfboard/httpd.log";
  37. char mimefile[1024] = "/etc/surfboard/mime.conf";
  38. char mime_default[512] = "text/plain";
  39. char dirindex[1024] = "index.html";
  40.  
  41. int myport=80;
  42. int uid=99; /* "nobody" on my machine */
  43. int gid=99; /* "nogroup" for me */
  44.  
  45. int log_threshold=LOG_MSG; /* By default, log everything bar debugs */
  46. int header_max=1024;
  47.  
  48. void process(int, char *, int);
  49. void readconf(void);
  50. void log_msg(int level, char * msg);
  51.  
  52. char * getextension(char *);
  53. void cgi_setenv(char **, char *, char *);
  54. void getmime(char *, char *, char *);
  55. void dumperror(int, int, char *);
  56. void mk_index(int, char *, char *, int);
  57. void fillout_header(char *);
  58. void add2header(char*, char *);
  59. char readstr(int, char *, int);
  60. void writestr(int, char *);
  61. void chomp(char *);
  62. int stripqmark(char *);
  63. int setupsock(void);
  64. void fireman(void);
  65.  
  66. main(int argc, char * argv[])
  67. {
  68.   int s, a; 
  69.  
  70.   if(argc>1) { strcpy(conffile, argv[1]); }
  71.  
  72.   readconf();
  73.  
  74.   log_msg(LOG_MSG, "Surfboard started");
  75.  
  76.   if((s=setupsock())<0)
  77.   {
  78.     log_msg(LOG_ERR, "Could not open socket");
  79.     perror("Could not open socket");
  80.     return 1;
  81.   }
  82.  
  83.   signal(SIGCHLD, fireman);
  84.  
  85.   if(fork()) { exit(0); }
  86.  
  87.   while(1)
  88.   {
  89.     int ns;
  90.     while((ns=accept(s, NULL, NULL))<0);
  91.     if(!fork()) {
  92.       close(ns);
  93.     } else { 
  94.       if(uid) { setuid(uid); }
  95.       if(gid) { setgid(gid); }
  96.       process(ns, docroot, s);
  97.       exit(0);
  98.     }
  99.   }
  100. }
  101. /************************************************************************/
  102. void process(int s, char * docroot, int orgs)
  103. {
  104.   char * http_header;
  105.   char http_version[10]="NONE";
  106.   int do_header=0;
  107.   char rawreq[1024];
  108.   char content_type[512];
  109.   char handler[1024]="dump";
  110.   char req[2048];
  111.   char method[10];
  112.   char buf[2048];
  113.  
  114.   int methodok=0;
  115.  
  116.   struct stat file_inf;
  117.  
  118.   log_msg(LOG_DEBUG, "Request received");
  119.  
  120.  
  121.   http_header=(char *)malloc(header_max * sizeof(char));
  122.   http_header[0]='\0';
  123.  
  124.   readstr(s, method, 10);
  125.   
  126.   if(!strcmp(method, "GET"))
  127.   {
  128.     methodok=1;
  129.   }
  130.  
  131.   if(!methodok)
  132.   {
  133.     sprintf(buf, "Unknown method \"%s\", bailing out with a 400", method);
  134.     log_msg(LOG_ERR, buf);
  135.     add2header(http_header, "HTTP/1.1 400 Bad Request\r\n");
  136.     fillout_header(http_header);
  137.     add2header(http_header, "Content-type: text/html\r\n\r\n");
  138.     if(do_header) { writestr(s, http_header); }
  139.     dumperror(s, 400, "");
  140.     exit(0);
  141.   }
  142.  
  143.   if(readstr(s, rawreq, 1024)==' ')
  144.   {
  145.     char c=' ', oldc='\n';
  146.  
  147.     readstr(s, http_version, 10);
  148.     do_header=1;
  149.     
  150.     /* Flush the browser options - perhaps I'll take some notice of them
  151.        sometime ;-)
  152.     */
  153.     while(1)
  154.     {
  155.       while(read(s, &c, 1)<1);
  156.       if(c=='\r') { continue; }
  157.       if(c=='\n' && oldc=='\n') { break; }
  158.       oldc=c;
  159.     }
  160.   } else {
  161.     do_header=0;
  162.   }
  163.  
  164.   sprintf(buf, "Asked for %s", rawreq);
  165.   log_msg(LOG_DEBUG, buf);
  166.  
  167.   if(strstr(rawreq, "..") || strstr(rawreq, "`"))
  168.   {
  169.     log_msg(LOG_ERR, "Relative path and/or shell escape - ATTACK ATTEMPT");
  170.     add2header(http_header, "HTTP/1.1 400 Bad Request\r\n");
  171.     fillout_header(http_header);
  172.     add2header(http_header, "Content-type: text/html\r\n\r\n");
  173.     if(do_header) { writestr(s, http_header); }
  174.     dumperror(s, 400, "");
  175.     exit(0);
  176.   }
  177.  
  178.   strcpy(req, docroot);
  179.   strcat(req, rawreq);
  180.   if(strstr(req, "?"))
  181.   {
  182.     char * p;
  183.     p=(char *)strstr(req, "?");
  184.     *p='\0';
  185.   }
  186.  
  187.   errno=0;
  188.  
  189.   stat(req, &file_inf);
  190.  
  191.   if(errno==ENOENT)
  192.   {
  193.     add2header(http_header, "HTTP/1.1 404 Not Found\r\n");
  194.     fillout_header(http_header);
  195.     add2header(http_header, "Content-type: text/html\r\n\r\n");
  196.     if(do_header) { writestr(s, http_header); }
  197.     sprintf(buf, "%s %s %s 404", method, rawreq, http_version);
  198.     log_msg(LOG_REQ, buf);
  199.     dumperror(s, 404, rawreq);
  200.     exit(0);
  201.   }
  202.   if(S_ISDIR(file_inf.st_mode))
  203.   {
  204.     log_msg(LOG_DEBUG, "Indexing directory");
  205.  
  206.     mk_index(s, req, rawreq, do_header);
  207.     /* also handles redirect to put slashes on dir names*/
  208.  
  209.     sprintf(buf, "Finished indexing, now requesting %s", req);
  210.     log_msg(LOG_DEBUG, buf);
  211.   }
  212.  
  213.   log_msg(LOG_DEBUG, "Determining MIME type...");
  214.  
  215.   getmime(req, content_type, handler);
  216.  
  217.   sprintf(buf, "Determined MIME type: %s (action:%s)", content_type, handler);
  218.   log_msg(LOG_DEBUG, buf);
  219.  
  220.   if(!strcmp(handler, "dump"))
  221.   {
  222.     int rdhandle;
  223.  
  224.     log_msg(LOG_DEBUG, "Dumping file");
  225.     errno=0;
  226.  
  227.     rdhandle=open(req, O_RDONLY);
  228.     switch(errno)
  229.     {
  230.       case(0) : { break; }
  231.       default : {
  232.         add2header(http_header, "HTTP/1.1 499 Unknown Error\r\n");
  233.         fillout_header(http_header);
  234.         add2header(http_header, "Content-type: text/html\r\n\r\n");
  235.         if(do_header) { writestr(s, http_header); }
  236.         sprintf(buf, "%s %s %s 499", method, rawreq, http_version);
  237.         log_msg(LOG_REQ, buf);
  238.         dumperror(s, 499, rawreq);
  239.         exit(0);
  240.                 }
  241.     }
  242.  
  243.     http_header[0]='\0';
  244.     add2header(http_header, "HTTP/1.1 200 OK\r\n");
  245.     fillout_header(http_header);
  246.     add2header(http_header, "Content-type: ");
  247.     add2header(http_header, content_type);
  248.     add2header(http_header, "\r\n\r\n");
  249.     if(do_header) { writestr(s, http_header); }
  250.     sprintf(buf, "%s %s %s 200", method, rawreq, http_version);
  251.     log_msg(LOG_REQ, buf);
  252.     stat(req, &file_inf);
  253.     while(file_inf.st_size>0)
  254.     {
  255.       int dlen;
  256.       dlen=read(rdhandle, buf, 1024);
  257.       file_inf.st_size-=dlen;
  258.       write(s, buf, dlen);
  259.     }
  260.     close(rdhandle);
  261.     log_msg(LOG_DEBUG, "File closed, going to the big exit statement in the sky...");
  262.   }
  263.  
  264.   if(handler[0]=='/' || !strcmp(handler, "cgi") || !strcmp(handler, "cgi-nph"))
  265.   {
  266.     int qpos=0;
  267.     char * cgienv[CGI_ENV_LEN];
  268.     char path[1024];
  269.  
  270.     strcpy(path, req);
  271.     for(qpos=strlen(path)-1; qpos>0; qpos--)
  272.     {
  273.        if(path[qpos]=='/') { break; }
  274.        path[qpos]='\0';
  275.     }
  276.     chdir(path);
  277.  
  278.     log_msg(LOG_DEBUG, "Identified as CGI script/handler");
  279.  
  280.     if(handler[0]=='/') { stat(handler, &file_inf); }
  281.  
  282.     if(!(file_inf.st_mode&S_IXOTH))
  283.     {
  284.       http_header[0]='\0';
  285.       if(do_header)
  286.       {
  287.         add2header(http_header, "HTTP/1.1 403 Forbidden\r\n");
  288.         fillout_header(http_header);
  289.         add2header(http_header, "Content-type: text/html\r\n\r\n");
  290.         writestr(s, http_header);
  291.       }
  292.       sprintf(buf, "%s %s %s 403", method, rawreq, http_version);
  293.       log_msg(LOG_REQ, buf);
  294.       dumperror(s, 403, rawreq);
  295.       exit(0);
  296.     }
  297.  
  298.     if(!strcmp(handler, "cgi"))
  299.     {
  300.       log_msg(LOG_DEBUG, "Not NPH, building header");
  301.       http_header[0]='\0';
  302.       add2header(http_header, "HTTP/1.1 200 OK\r\n");
  303.       fillout_header(http_header);
  304.       writestr(s, http_header); /* Broken if HTTP/x.x not specified! */
  305.     }
  306.     close(1); /* stdout */
  307.     log_msg(LOG_DEBUG, "stdout closed");
  308.  
  309.     if(dup(s)!=1)
  310.     {
  311.       log_msg(LOG_ERR, "CGI script stdout redirection failed");
  312.       http_header[0]='\0';
  313.       add2header(http_header, "HTTP/1.1 500 Internal Server Error\r\n");
  314.       fillout_header(http_header);
  315.       if(do_header) { writestr(s, http_header); }
  316.       dumperror(s, 500, "");
  317.     }
  318.  
  319.     log_msg(LOG_DEBUG, "Setting up environment variables");
  320.  
  321.     cgienv[0]=NULL;
  322.  
  323.     /* Got this list from the CGI 1.1 specification
  324.     (http://hoohoo.ncsa.uiuc.edu/cgi/)
  325.     */
  326.     cgi_setenv(cgienv, "SERVER_SOFTWARE", VERSION);
  327.     cgi_setenv(cgienv, "SERVER_NAME", hostname);
  328.     cgi_setenv(cgienv, "GATEWAY_INTERFACE", "CGI/1.1");
  329.     cgi_setenv(cgienv, "SERVER_PROTOCOL", http_version);
  330.     sprintf(buf, "%d", myport);
  331.     cgi_setenv(cgienv, "SERVER_PORT", buf);
  332.     cgi_setenv(cgienv, "REQUEST_METHOD", method);
  333.     /*
  334.     Neither PATH_INFO nor PATH_TRANSLATED are set, as I haven't a clue
  335.     what they are! Any help to m_luff@wincoll.ac.uk
  336.     */
  337.     log_msg(LOG_DEBUG, "Stripping arguments...");
  338.     qpos=stripqmark(rawreq);
  339.     cgi_setenv(cgienv, "SCRIPT_NAME", rawreq);
  340.     log_msg(LOG_DEBUG, "Stripped arguments OK");
  341.     /* cgi_setenv(cgienv, "REMOTE_ADDR", ); */        /* STORE IT */
  342.     /* cgi_setenv(cgienv, "REMOTE_HOST", );  - Leaving unset */
  343.     /* AUTH_TYPE is not set */
  344.     /* REMOTE_USER is not set */
  345.     /* REMOTE_IDENT is not set */
  346.     /* CONTENT_TYPE is not set */
  347.     /* CONTENT_LENGTH is not set */
  348.  
  349.     /* One day I'll put in HTTP_xxx from the client */
  350.  
  351.     if(handler[0]=='/')
  352.     {
  353.       log_msg(LOG_DEBUG, "Launching CGI handler");
  354.       cgi_setenv(cgienv, "QUERY_STRING", rawreq+qpos);
  355.       execle(handler, handler, req, NULL, cgienv);
  356.     } else if(strstr(rawreq+qpos, "=") || *(rawreq+qpos)=='\0') {
  357.       log_msg(LOG_DEBUG, "Query string");
  358.       cgi_setenv(cgienv, "QUERY_STRING", rawreq+qpos);
  359.       execle(req, req, NULL, cgienv);
  360.     } else {
  361.       log_msg(LOG_DEBUG, "Command-line option");
  362.       execle(req, req, rawreq+qpos, NULL, cgienv);
  363.     }
  364.     log_msg(LOG_ERR, "execle() call returned!");
  365.     perror("execle()");
  366.     dup(2); /* stderr is copied onto the first free descriptor - stdout,
  367.         in case something went wrong */
  368.   }
  369.  
  370.   free(http_header);
  371.   close(s);
  372. }
  373. /************************************************************************/
  374. void dumperror(int s, int num, char * req)
  375. {
  376.   char buf[1024];
  377.  
  378.   switch(num)
  379.   {
  380.     case(400) : {
  381.       writestr(s, "<HTML>\n<HEAD><TITLE>400 Bad Request</TITLE></HEAD>\n");
  382.       writestr(s, "<BODY>\n<H1 ALIGN=CENTER>400 Bad Request</H1>\n");
  383.       writestr(s, "<P ALIGN=CENTER><I>Your client sent an invalid request, ");
  384.       writestr(s, "or one which the server cannot deal with.</I></P>\n");
  385.       writestr(s, "<P ALIGN=RIGHT>" VERSION "</P>\n</BODY>\n</HTML>\n");
  386.       close(s);
  387.       break;
  388.                 }
  389.  
  390.     case(403) : {
  391.       writestr(s, "<HTML>\n<HEAD><TITLE>403 Permission Denied</TITLE></HEAD>\n");
  392.       writestr(s, "<BODY>\n<H1 ALIGN=CENTER>403 Permission Denied</H1>\n");
  393.       writestr(s, "<P ALIGN=CENTER><I>You do not have permission to ");
  394.       sprintf(buf, "access %s on this server</I></P>\n<P ALIGN=RIGHT>" VERSION
  395.     "</P>\n</BODY>\n</HTML>\n", req);
  396.       writestr(s, buf);
  397.       close(s);
  398.       break;
  399.                 }
  400.  
  401.     case(404) : {
  402.       writestr(s, "<HTML>\n<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
  403.       writestr(s, "<BODY>\n<H1 ALIGN=CENTER>404 Not Found</H1>\n");
  404.       writestr(s, "<P ALIGN=CENTER><I>The specified file was not ");
  405.       writestr(s, "found</I></P>\n<P ALIGN=RIGHT>" VERSION
  406.     "</P>\n</BODY>\n</HTML>\n");
  407.       close(s);
  408.       break;
  409.                 }
  410.  
  411.     case(499) : {
  412.       writestr(s, "<HTML>\n<HEAD><TITLE>499 Unknown Error</TITLE></HEAD>\n");
  413.       writestr(s, "<BODY>\n<H1 ALIGN=CENTER>499 Unknown Error</H1>\n");
  414.       writestr(s, "<P ALIGN=CENTER><I>An error occurred while opening ");
  415.       writestr(s, "this file. What it is, I do not know! Contact ");
  416.       writestr(s, "the webmaster.</I></P>\n<P ALIGN=RIGHT>" VERSION
  417.     "</P>\n</BODY>\n</HTML>\n");
  418.       close(s);
  419.       break;
  420.                 }
  421.  
  422.     case(500) : {
  423.       writestr(s, "<HTML>\n<HEAD><TITLE>500 Internal Server Error</TITLE></HEAD>\n");
  424.       writestr(s, "<BODY>\n<H1 ALIGN=CENTER>500 Internal Server Error</H1>\n");
  425.       writestr(s, "<P ALIGN=CENTER><I>Something went wrong inside"
  426.     " the server. Perhaps a CGI script went awry, or something "
  427.     "in the bowels of the httpd is broken. Get your admin to check the "
  428.     "logfile for error messages.</I></P>\n<P ALIGN=RIGHT>" VERSION
  429.     "</P>\n</BODY>\n</HTML>\n");
  430.       close(s);
  431.       break;
  432.                 }
  433.  
  434.     default   : {
  435.       sprintf(buf, "<HTML>\n<HEAD><TITLE>%d - Unhandled HTTP Error"
  436.     "</TITLE></HEAD>\n<BODY><H1 ALIGN=CENTER>%d - Unhandled HTTP "
  437.     "Error</H1>\n<P ALIGN=CENTER><I>This is a bug in the web server. "
  438.     "The server has trapped an error and knows what went wrong, but " 
  439.     "the author has forgotten to write an explanation of this "
  440.     "error code. Mail Meredydd Luff (at <A "
  441.     "HREF=mailto:m_luff@wincoll.ac.uk>m_luff@wincoll.ac.uk</A>) "
  442.     "and tell him what happened.</I></P>\n<P ALIGN=RIGHT>" VERSION
  443.     "</P>\n</BODY>\n</HTML>\n", num, num);
  444.       writestr(s, buf);
  445.       close(s);
  446.       break;
  447.                 }
  448.   }
  449. }
  450. /************************************************************************/
  451. void cgi_setenv(char ** env, char * name, char * value)
  452. {
  453.   int a=0;
  454.   while(env[a]!=NULL) { a++; }
  455.   if(a==CGI_ENV_LEN-1)
  456.   {
  457.     char buf[1024];
  458.     sprintf(buf, "CGI environment full - cannot add %s=%s", name, value);
  459.     log_msg(LOG_ERR, buf);
  460.     return;
  461.   }
  462.   env[a+1]=NULL;
  463.   env[a]=(char *)malloc((strlen(name)+strlen(value)+64)*sizeof(char));
  464.   strcpy(env[a], name);
  465.   strcat(env[a], "=");
  466.   strcat(env[a], value);
  467. }
  468. /************************************************************************/
  469. void redirect(int s, char * from, char * to, int do_header)
  470. {
  471.   char buf[4096];
  472.   char * http_header;
  473.   http_header=(char *)malloc(header_max*sizeof(char));
  474.  
  475.   http_header[0]='\0';
  476.   add2header(http_header, "HTTP/1.1 301 Moved Permanently\r\n");
  477.   fillout_header(http_header);
  478.   add2header(http_header, "Location: ");
  479.   add2header(http_header, to);
  480.   add2header(http_header, "\r\n\r\n");
  481.   if(do_header) { writestr(s, http_header); }
  482.   sprintf(buf, "<HTML>\n<HEAD><TITLE>301 Moved Permanently</TITLE>"
  483.     "</HEAD>\n<BODY><H1 ALIGN=CENTER>301 Moved Permanently</H1>\n"
  484.     "<P ALIGN=CENTER><I>The URL %s has moved to <A HREF=\"%s\">%s</A>"
  485.     "</I></P>\n<P ALIGN=RIGHT>" VERSION "</P>\n</BODY>\n</HTML>\n",
  486.     from, to, to);
  487.   writestr(s, buf);
  488.   free(http_header);
  489. }
  490. /************************************************************************/
  491. void mk_index(int s, char * req, char * rawreq, int do_header)
  492. {
  493.   char buf[4096];
  494.   int pos=0;
  495.   int p=0, do404=0;
  496.  
  497.   struct stat file_inf;
  498.  
  499.   if(req[strlen(req)-1]!='/')
  500.   {
  501.     char http_header[1024]="";
  502.     char corrected[1024];
  503.  
  504.     strcpy(corrected, rawreq);
  505.     strcat(corrected, "/");
  506.     redirect(s, rawreq, corrected, do_header);
  507.     exit(0);
  508.   }
  509.  
  510.   errno=0;
  511.  
  512.   log_msg(LOG_DEBUG, "Trying:");
  513.  
  514.   do
  515.   {
  516.     strcpy(buf, req);
  517.  
  518.     p=pos;
  519.     while(!(dirindex[p]=='\0' || isspace(dirindex[p]))) { p++; }
  520.  
  521.     if(dirindex[p]=='\0') { do404=1; }
  522.     dirindex[p]='\0';
  523.     if(dirindex[pos]=='/')
  524.     { strcpy(buf, dirindex+pos); } else { strcat(buf, dirindex+pos); }
  525.  
  526.     log_msg(LOG_DEBUG, buf);
  527.  
  528.     errno=0;
  529.     stat(buf, &file_inf);
  530.  
  531.     if(S_ISDIR(file_inf.st_mode)) { errno=ENOENT; }
  532.  
  533.     pos=p+1;
  534.   } while(errno==ENOENT && !do404);
  535.  
  536.   if(do404 && errno==ENOENT)
  537.   {
  538.     char * http_header;
  539.     http_header=(char *)malloc(header_max*sizeof(char));
  540.     http_header[0]='\0';
  541.     add2header(http_header, "HTTP/1.1 404 Not Found\r\n");
  542.     fillout_header(http_header);
  543.     add2header(http_header, "Content-type: text/html\r\n\r\n");
  544.     if(do_header) { writestr(s, http_header); }
  545.     dumperror(s, 404, rawreq);
  546.     free(http_header);
  547.     exit(0);
  548.   } else {
  549.     strcpy(req, buf);
  550.   }
  551.  
  552. }
  553. /************************************************************************/
  554. void fillout_header(char * header)
  555. {
  556.   add2header(header, "Server: " VERSION "\r\n");
  557.   add2header(header, "Connection: close\r\n");
  558. }
  559. /************************************************************************/
  560. void getmime(char * req, char * content_type, char * handler)
  561. {
  562.   FILE * mime;
  563.   char buf[4096];
  564.  
  565.   strcpy(content_type, mime_default);
  566.   strcpy(handler, "dump");
  567.  
  568.   if((mime=fopen(mimefile, "r"))==NULL)
  569.   {
  570.     sprintf(buf, "Could not open MIME config file \"%s\", using default "
  571.     "content type %s\n", mimefile, mime_default);
  572.     log_msg(LOG_ERR, buf);
  573.     strcpy(content_type, mime_default);
  574.   } else {
  575.     char thisext[512];
  576.     char thistype[512];
  577.     char thishandler[1024];
  578.     char myext[512];
  579.  
  580.     strcpy(myext, getextension(req));
  581.     while(!feof(mime))
  582.     {
  583.       fscanf(mime, " %s", thisext);
  584.       if(thisext[0]=='#') { while(getc(mime)!='\n'); continue; }
  585.       fscanf(mime, " %s ", thistype);
  586.       fgets(thishandler, 1024, mime);
  587.       chomp(thishandler);
  588.       if(!strcmp(myext, thisext))
  589.       { strcpy(content_type, thistype); strcpy(handler, thishandler); break; }
  590.     }
  591.     fclose(mime);
  592.   }
  593. }
  594. /************************************************************************/
  595. void add2header(char * header, char * line)
  596. {
  597.   if(strlen(header)+strlen(line)+1>header_max)
  598.   {
  599.     log_msg(LOG_ERR, "Header exceeded max length, line ignored");
  600.   } else {
  601.     strcat(header, line);
  602.   }
  603. }
  604. /************************************************************************/
  605. void readconf(void)
  606. {
  607.   FILE * conf;
  608.   char cmd[512];
  609.   char buf[1600];
  610.  
  611.   sprintf(buf, "Reading config from file \"%s\"", conffile);
  612.   log_msg(LOG_DEBUG, buf);
  613.  
  614.   if((conf=fopen(conffile, "r"))==NULL)
  615.   {
  616.     sprintf(buf, "Could not open config file \"%s\"", conffile);
  617.     log_msg(LOG_ERR, buf);
  618.     fprintf(stderr, "%s\n", buf);
  619.     exit(1);
  620.   }
  621.  
  622.   while(1)
  623.   {
  624.     fscanf(conf, " %s ", cmd);
  625.     if(feof(conf)) { break; }
  626.     if(cmd[0]=='#') { while(getc(conf)!='\n'); continue; }
  627.  
  628.     if(!strcmp(cmd, "Port"))
  629.     {
  630.       fscanf(conf, " %d", &myport);
  631.       continue;
  632.     }
  633.  
  634.     if(!strcmp(cmd, "DocRoot"))
  635.     {
  636.       fscanf(conf, " %s", docroot);
  637.       continue;
  638.     }
  639.  
  640.     if(!strcmp(cmd, "LogFile"))
  641.     {
  642.       fscanf(conf, " %s", logfile);
  643.       continue;
  644.     }
  645.  
  646.     if(!strcmp(cmd, "LogThreshold"))
  647.     {
  648.       fscanf(conf, " %d", &log_threshold);
  649.       continue;
  650.     }
  651.  
  652.     if(!strcmp(cmd, "MimeFile"))
  653.     {
  654.       fscanf(conf, " %s", mimefile);
  655.       continue;
  656.     }
  657.  
  658.     if(!strcmp(cmd, "DefaultMime"))
  659.     {
  660.       fscanf(conf, " %s", mime_default);
  661.       continue;
  662.     }
  663.  
  664.     if(!strcmp(cmd, "SetUID"))
  665.     {
  666.       fscanf(conf, " %d", &uid);
  667.       continue;
  668.     }
  669.  
  670.     if(!strcmp(cmd, "SetGID"))
  671.     {
  672.       fscanf(conf, " %d", &gid);
  673.       continue;
  674.     }
  675.  
  676.     if(!strcmp(cmd, "DirIndex"))
  677.     {
  678.       fgets(dirindex, 1024, conf);
  679.       chomp(dirindex);
  680.       continue;
  681.     }
  682.  
  683.     fprintf(stderr, "Surfboard - Invalid config option \"%s\"\n", cmd);
  684.     fclose(conf);
  685.     exit(1);
  686.   }
  687.   fclose(conf);
  688.   log_msg(LOG_DEBUG, "Finished reading config file");
  689. }
  690. /************************************************************************/
  691. void log_msg(int level, char * str)
  692. {
  693.   if(level>=log_threshold)
  694.   {
  695.     if(!strcmp(logfile, "-"))
  696.     {
  697.       fprintf(stderr, "Surfboard - Log level %d: %s\n", level, str);
  698.     } else {
  699.       FILE * logfileptr;
  700.       int a;
  701.       time_t now;
  702.  
  703.       time(&now);
  704.  
  705.       for(a=0; a<5; a++)
  706.       {
  707.         logfileptr=fopen(logfile, "a");
  708.         if(logfileptr==NULL) { continue; }
  709.         fprintf(logfileptr, "%d %s%s\n", level, ctime(&now), str);
  710.         fclose(logfileptr);
  711.         return;
  712.       }
  713.       printf("Surfboard - Cannot open logfile!\a\n");
  714.       perror("Surfboard - Cannot open logfile!\a");
  715.       printf("Surfboard - Log level %d: %s\n", level, str);
  716.     }
  717.   }
  718. }
  719. /************************************************************************/
  720. char * getextension(char * s)
  721. {
  722.   char scopy[1024];
  723.   char * retval;
  724.   
  725.   strcpy(scopy, s);
  726.   retval=strstr(scopy, "?");
  727.   if(retval==NULL)
  728.   { retval=scopy+strlen(s); } else { *retval='\0'; }
  729.   
  730.   while(1)
  731.   {
  732.     retval--;
  733.     if(*retval=='.')
  734.     {     log_msg(LOG_DEBUG, retval+1);
  735.  return (retval+1); }
  736.     if(retval==scopy) { return s; }
  737.   }
  738. }
  739. /************************************************************************/
  740. void writestr(int s, char * buf)
  741. {
  742.   write(s, buf, strlen(buf));
  743. }
  744. /************************************************************************/
  745. void chomp(char * s)
  746. {
  747.   if(s[0]=='\0') { return; }
  748.   if(s[strlen(s)-1]=='\n') { s[strlen(s)-1]='\0'; }
  749. }
  750. /************************************************************************/
  751. int stripqmark(char * s)
  752. {
  753.   int pos=0;
  754.  
  755.   do
  756.   {
  757.     if(s[pos]=='?') { s[pos]='\0'; return pos+1; }
  758.     pos++;
  759.   } while(s[pos]!='\0');
  760.   return pos;
  761. }
  762. /************************************************************************/
  763. char readstr(int s, char * buf, int maxlen)
  764. {
  765.   char c;
  766.   int pos=0;
  767.   
  768.   while(1)
  769.   {
  770.     while(read(s, &c, 1)<1);
  771.     if(c=='\r') { continue; } /* There's a \n coming... */
  772.     if(isspace(c) || pos==maxlen-1) { buf[pos]='\0'; return c; }
  773.     buf[pos]=c;
  774.     pos++;
  775.   }
  776. }
  777. /************************************************************************/
  778. int setupsock(void)
  779. {
  780.   int s;
  781.   struct sockaddr_in myopen;
  782.   struct hostent *hp;
  783.  
  784.   memset(&myopen, 0, sizeof(struct sockaddr_in)); /* clear my address */
  785.   gethostname(hostname, 1024);                  /* who are we? (also
  786.                            store for later) */
  787.   hp= gethostbyname(hostname);                  /* get our address info */
  788.   if (hp == NULL)                             /* we don't exist !? */
  789.     return(-1);
  790.   myopen.sin_family= hp->h_addrtype;              /* this is our host address */
  791.   myopen.sin_port= htons(myport);                 /* this is our port number */
  792.   if ((s= socket(AF_INET, SOCK_STREAM, 0)) < 0) /* create socket */
  793.     return(-1);
  794.   if (bind(s,(struct sockaddr *)&myopen,sizeof(struct sockaddr_in)) < 0) {
  795.     close(s);
  796.     return(-1);                               /* bind address to socket */
  797.   }
  798.   listen(s, 3);                               /* max # of queued connects */
  799.   return(s);
  800. }
  801. /*************************************************************************/
  802. /* Fireman - anti-zombie code. Greek to me, but it works ;-) */
  803. void fireman(void)
  804. {
  805.   while (waitpid(-1, NULL, WNOHANG) > 0);
  806. }
  807.